package com.sharad.quizbowl.ui.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.common.base.Joiner;
import com.sharad.quizbowl.ui.dao.dao.TossupsDao;
import com.sharad.quizbowl.ui.dao.dto.Tossups;
import com.sharad.quizbowl.ui.dao.factory.TossupsDaoFactory;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class QueryServlet extends HttpServlet {

	private static final long serialVersionUID = 7908000003624588547L;
	private ArrayList<String> queryTerms;
	private ArrayList<String> queryValues;
	private PrintWriter writer;

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		TossupsDao dao = TossupsDaoFactory.create();
		writer = null;
		response.setContentType("text/javascript;charset=utf-8");
		String alt = request.getParameter("alt");
		try {
			writer = response.getWriter();
			try {
				queryTerms = new ArrayList<String>();
				queryValues = new ArrayList<String>();

				if (request.getParameter("condition") != null) {
					if (request.getParameter("condition").equals("all")) {
						queryTerms.add("answer like ? or question like ?");
						queryValues.add("%"
								+ request.getParameter("answer").replaceAll(
										" ", "%") + "%");
						queryValues.add("%"
								+ request.getParameter("answer").replaceAll(
										" ", "%") + "%");
					}
				} else {
					if (request.getParameter("answer") != null) {
						queryTerms.add("answer like ?");
						queryValues.add("%"
								+ request.getParameter("answer").replaceAll(
										" ", "%") + "%");
					} else {
						queryTerms.add("answer like ?");
						queryValues.add("%%");
					}
					if (request.getParameter("question") != null) {
						queryTerms.add("question like ?");
						queryValues.add("%"
								+ request.getParameter("question").replaceAll(
										" ", "%") + "%");
					}
				}
				if (request.getParameter("tournament") != null) {
					addQueryTerm("tournament",
							request.getParameter("tournament"), "like");

				}

				if (request.getParameter("round") != null) {
					addQueryTerm("round", request.getParameter("round"), "like");
				}
				if (request.getParameter("year") != null) {
					addQueryTerm("year", request.getParameter("year"), "=");

				}
				if (request.getParameter("category") != null) {
					addQueryTerm("category", request.getParameter("category"),
							"like");

				}
				if (request.getParameter("questionNum") != null) {
					addQueryTerm("question_num",
							request.getParameter("questionNum"), "=");
				}
				if (request.getParameter("difficulty") != null) {
					addQueryTerm("difficulty",
							request.getParameter("difficulty"), "like");

				}

				String queryString = Joiner.on(" and ").join(queryTerms)
						+ (queryTerms.size() != 0 ? " " : "");
				if (request.getParameter("random") != null) {
					if (request.getParameter("random").equals("true")) {
						if (request.getParameter("limit") != null)
							queryString += "order by rand() limit "
									+ request.getParameter("limit");
						else
							queryString += "order by rand() limit 1";

					}
				} else {
					if (request.getParameter("limit") != null)
						queryString += "limit " + request.getParameter("limit");
					else
						queryString += "order by year DESC, tournament ASC";
				}
				Tossups[] s = dao.findByDynamicWhere(queryString,
						queryValues.toArray(new String[] {}));
				XStream xstream = null;
				if (s.length != 0) {
					if (alt == null) {
						xstream = new XStream(new DomDriver());
						xstream.setMode(XStream.NO_REFERENCES);
						xstream.alias("tossup", Tossups.class);
						writer.print(xstream.toXML(s));
					} else if (alt.equals("json-in-script")) {
						xstream = new XStream(
								new JsonHierarchicalStreamDriver());
						xstream.setMode(XStream.NO_REFERENCES);
						xstream.alias("tossup", Tossups.class);
						writer.print((request.getParameter("callback") == null ? "callback"
								: request.getParameter("callback"))
								+ "(");
						writer.print(xstream.toXML(s));
						writer.print(")");
					}
				} else {
					Error e = new Error("No results found.");
					if (alt == null) {
						xstream = new XStream(new DomDriver());
					} else if (alt.equals("json-in-script")) {
						xstream = new XStream(
								new JsonHierarchicalStreamDriver());

					}
					xstream.setMode(XStream.NO_REFERENCES);
					xstream.alias("error", Error.class);
					writer.print(xstream.toXML(e));
//					response.sendError(HttpServletResponse.SC_NOT_FOUND,
//							"No results.");
				}

			} catch (Throwable e) {
				writer.print("Error: query did not work!\n");
				writer.print(e.getMessage());

			}
			writer.flush();
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public void addQueryTerm(String term, String value, String comparator) {

		String[] temp = value.replaceAll("\\\\\\|", "###").split("\\|");
		String delimiter = "";
		StringBuilder sb = new StringBuilder();
		sb.append("(");
		for (int i = 0; i < temp.length; i++) {
			if (term.equals("tournament")) {
				sb.append(delimiter).append("year" + " " + "=" + " ?");
				temp[i] = temp[i].replaceAll("###", "|");
				queryValues.add(temp[i].substring(0, temp[i].indexOf(" "))
						.trim());
				temp[i] = temp[i].substring(temp[i].indexOf(" ")).trim();
				sb.append(" and ").append(term + " " + comparator + " ?");
				queryValues.add(temp[i]);
			} else {
				sb.append(delimiter).append(term + " " + comparator + " ?");
				queryValues.add(temp[i].replaceAll("###", "|"));
			}
			delimiter = " or ";

		}
		sb.append(")");
		queryTerms.add(sb.toString());

	}

	static class Error {
		private String message;

		public Error(String message) {
			this.message = message;
		}

		public String getMessage() {
			return message;
		}
	}
}
